/**
 * 文件名: atomic_fetch_add_test.cpp
 *
 * 功能:
 *   演示 std::atomic<int>::fetch_add 在多线程环境中的线程安全性。
 *   通过多个线程对同一计数器执行自增操作，最终结果必须确定。
 *
 * 编译运行示例:
 *   g++ -std=c++20 -pthread atomic_fetch_add_test.cpp -lgtest -lgtest_main -o atomic_fetch_add_test
 *   ./atomic_fetch_add_test
 */

#include <gtest/gtest.h>

#include <atomic>
#include <thread>
#include <vector>

// 基础背景：
// - counter 使用 std::atomic<int>，初始化为 0。
// - 多个线程各自执行固定次数的自增，使用 fetch_add 保证原子性。
// - 期望最终计数器值等于线程数 * 每线程自增次数。
TEST(AtomicFetchAdd, IncrementsAreThreadSafe) {
    // 共享计数器，采用 relaxed 内存序，因为只关心最终计数，不涉及跨线程的数值可见性顺序。
    std::atomic<int> counter{0};

    constexpr int kThreadCount = 6;
    constexpr int kIncrementsPerThread = 2'000;

    // 工作任务：循环调用 fetch_add(1)
    auto worker = [&]() {
        for (int i = 0; i < kIncrementsPerThread; ++i) {
            counter.fetch_add(1, std::memory_order_relaxed);
        }
    };

    std::vector<std::thread> threads;
    threads.reserve(kThreadCount);

    // 创建并启动线程
    for (int i = 0; i < kThreadCount; ++i) {
        threads.emplace_back(worker);
    }

    // 等待所有线程结束，避免主线程提前退出
    for (auto& t : threads) {
        t.join();
    }

    // 验证结果：原子操作确保不会丢失任何一次自增
    EXPECT_EQ(counter.load(std::memory_order_relaxed),
              kThreadCount * kIncrementsPerThread);
}